package net.wsnetwork.jawa.common;

import java.io.IOException;
import java.io.OutputStream;

public class ChunkedOutputStream extends OutputStream {
    private static final byte[] ZERO = "0".getBytes(Constants.UTF_8);
    private static final byte[] ONE = "1".getBytes(Constants.UTF_8);
    private static final byte[] CHUNK_END = Constants.NEWLINE.getBytes(Constants.UTF_8);
    private final OutputStream out;

    public ChunkedOutputStream(OutputStream out) {
        this.out = out;
    }

    @Override public void write(int b) throws IOException {
        out.write(ONE);
        out.write(CHUNK_END);
        out.write(b);
        out.write(CHUNK_END);
    }

    @Override public void write(byte b[], int off, int len) throws IOException {
        if (b == null) {
            throw new NullPointerException();
        } else if ((off < 0) || (off > b.length) || (len < 0) ||
                ((off + len) > b.length) || ((off + len) < 0)) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return;
        }

        String lengthString = Integer.toHexString(len).toUpperCase();
        out.write(lengthString.getBytes(Constants.UTF_8));
        out.write(CHUNK_END);
        out.write(b, off, len);
        out.write(CHUNK_END);
    }

    /**
     * Finishes writing data chunks without closing the wrapped output stream.
     */
    public void finish() throws IOException {
        out.write(ZERO);
        out.write(CHUNK_END);
        out.write(CHUNK_END);
    }

    @Override public void close() throws IOException {
        finish();
        out.close();
    }
}
